//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package user_todo_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/user_dao"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/user_todo_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

type UserTodoApiImpl struct {
	user_todo_api.UnimplementedUserTodoApiServer
}

func (apiImpl *UserTodoApiImpl) CreateTodo(ctx context.Context, req *user_todo_api.CreateTodoRequest) (*user_todo_api.CreateTodoResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_todo_api.CreateTodoResponse{
			Code:   user_todo_api.CreateTodoResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	todoId := uuid.NewString()

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = user_dao.UserTodoDao.Insert(sessCtx, &user_dao.TodoInfoDbItem{
			TodoId: todoId,
			UserId: sessionItem.UserId,
			BasicInfo: user_dao.BasicTodoInfoDbItem{
				Title:      req.BasicInfo.Title,
				TitleColor: req.BasicInfo.TitleColor,
				Done:       req.BasicInfo.Done,
			},
			CreateTime: nowTime,
			UpdateTime: nowTime,
		})
		if err != nil {
			return nil, err
		}
		return &user_todo_api.CreateTodoResponse{
			Code:   user_todo_api.CreateTodoResponse_CODE_OK,
			TodoId: todoId,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	return ret.(*user_todo_api.CreateTodoResponse), nil
}

func (apiImpl *UserTodoApiImpl) UpdateTodo(ctx context.Context, req *user_todo_api.UpdateTodoRequest) (*user_todo_api.UpdateTodoResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_todo_api.UpdateTodoResponse{
			Code:   user_todo_api.UpdateTodoResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	exist, err := user_dao.UserTodoDao.Exist(ctx, sessionItem.UserId, req.TodoId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &user_todo_api.UpdateTodoResponse{
			Code:   user_todo_api.UpdateTodoResponse_CODE_NO_TODO,
			ErrMsg: "待办事项不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = user_dao.UserTodoDao.Update(sessCtx, sessionItem.UserId, req.TodoId,
			&user_dao.BasicTodoInfoDbItem{
				Title:      req.BasicInfo.Title,
				TitleColor: req.BasicInfo.TitleColor,
				Done:       req.BasicInfo.Done,
			}, nowTime)
		if err != nil {
			return nil, err
		}
		return &user_todo_api.UpdateTodoResponse{
			Code: user_todo_api.UpdateTodoResponse_CODE_OK,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	return ret.(*user_todo_api.UpdateTodoResponse), nil
}

func (apiImpl *UserTodoApiImpl) CountTodo(ctx context.Context, req *user_todo_api.CountTodoRequest) (*user_todo_api.CountTodoResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_todo_api.CountTodoResponse{
			Code:   user_todo_api.CountTodoResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	totalCount, err := user_dao.UserTodoDao.Count(ctx, sessionItem.UserId, false, false)
	if err != nil {
		return nil, err
	}
	doneCount, err := user_dao.UserTodoDao.Count(ctx, sessionItem.UserId, true, true)
	if err != nil {
		return nil, err
	}
	return &user_todo_api.CountTodoResponse{
		Code:       user_todo_api.CountTodoResponse_CODE_OK,
		TotalCount: totalCount,
		DoneCount:  doneCount,
	}, nil
}

func (apiImpl *UserTodoApiImpl) ListTodo(ctx context.Context, req *user_todo_api.ListTodoRequest) (*user_todo_api.ListTodoResponse, error) {
	emptyList := []*user_todo_api.TodoInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_todo_api.ListTodoResponse{
			Code:     user_todo_api.ListTodoResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			TodoList: emptyList,
		}, nil
	}

	todoItemList, err := user_dao.UserTodoDao.List(ctx, sessionItem.UserId)
	if err != nil {
		return nil, err
	}

	todoList := []*user_todo_api.TodoInfo{}
	for _, todoItem := range todoItemList {
		todoList = append(todoList, todoItem.ToTodoInfo())
	}

	return &user_todo_api.ListTodoResponse{
		Code:     user_todo_api.ListTodoResponse_CODE_OK,
		TodoList: todoList,
	}, nil
}

func (apiImpl *UserTodoApiImpl) GetTodo(ctx context.Context, req *user_todo_api.GetTodoRequest) (*user_todo_api.GetTodoResponse, error) {
	emptyInfo := &user_todo_api.TodoInfo{
		BasicInfo: &user_todo_api.BasicTodoInfo{},
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_todo_api.GetTodoResponse{
			Code:   user_todo_api.GetTodoResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
			Todo:   emptyInfo,
		}, nil
	}
	todoItem, err := user_dao.UserTodoDao.Get(ctx, sessionItem.UserId, req.TodoId)
	if err != nil {
		return &user_todo_api.GetTodoResponse{
			Code:   user_todo_api.GetTodoResponse_CODE_NO_TODO,
			ErrMsg: "待办事项不存在",
			Todo:   emptyInfo,
		}, nil
	}
	return &user_todo_api.GetTodoResponse{
		Code: user_todo_api.GetTodoResponse_CODE_OK,
		Todo: todoItem.ToTodoInfo(),
	}, nil
}

func (apiImpl *UserTodoApiImpl) RemoveTodo(ctx context.Context, req *user_todo_api.RemoveTodoRequest) (*user_todo_api.RemoveTodoResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_todo_api.RemoveTodoResponse{
			Code:   user_todo_api.RemoveTodoResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = user_dao.UserTodoDao.Remove(sessCtx, sessionItem.UserId, req.TodoId)
		if err != nil {
			return nil, err
		}
		return &user_todo_api.RemoveTodoResponse{
			Code: user_todo_api.RemoveTodoResponse_CODE_OK,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	return ret.(*user_todo_api.RemoveTodoResponse), nil
}

func (apiImpl *UserTodoApiImpl) ClearTodo(ctx context.Context, req *user_todo_api.ClearTodoRequest) (*user_todo_api.ClearTodoResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_todo_api.ClearTodoResponse{
			Code:   user_todo_api.ClearTodoResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = user_dao.UserTodoDao.RemoveByUser(sessCtx, sessionItem.UserId)
		if err != nil {
			return nil, err
		}
		return &user_todo_api.ClearTodoResponse{
			Code: user_todo_api.ClearTodoResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*user_todo_api.ClearTodoResponse), nil
}
